// 生成随机颜色的函数，确保不与已有颜色重复
/**
 *
 * @param {[string]} existingColors 存在的颜色值数组
 * @param {number}  seed 随机种子，默认值为0
 * @param {number}  roleNum 角色数量，默认值为3
 * @returns {string} 随机颜色值
 */
export const generateRandomColor = (existingColors, seed = 0, roleNum = 3) => {
  // 预设一组明亮且区分度高的基础颜色
  // const baseColors = [
  //   '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FECA57',
  //   '#FF9FF3', '#54A0FF', '#5F27CD', '#00D2D3', '#FF9F43',
  //   '#10AC84', '#5F27CD', '#54A0FF', '#FF9FF3', '#FECA57'
  // ];
  const baseColors = [];

  // 如果基础颜色还没用完，优先使用基础颜色以保证颜色的美观性和区分度
  if (seed < baseColors.length) {
    const color = baseColors[seed];
    // 检查基础颜色是否已被使用
    if (!existingColors.includes(color)) {
      return color;
    }
  }

  // 如果基础颜色已用完或已被使用，则生成随机颜色
  let randomColor;
  const hueStep = Math.max(30, 360 / roleNum); // 最小30度的间隔
  const baseHue = (seed * hueStep) % 360;

  // 循环直到找到一个不重复的颜色
  do {
    // 优化2: 增加色调的随机范围，使颜色分布更广
    const hueVariation = Math.floor(Math.random() * 120) - 60; // ±60度的变化范围
    const hue = (baseHue + hueVariation + 360) % 360; // 确保是正数

    // 优化3: 调整饱和度和亮度范围，使颜色更加鲜明
    // 根据色调位置动态调整饱和度和亮度，使颜色更和谐
    let saturation, lightness;

    // 高饱和度区（红、绿、蓝附近）
    if ((hue >= 0 && hue < 30) || (hue >= 120 && hue < 150) || (hue >= 240 && hue < 270)) {
      saturation = 80 + Math.floor(Math.random() * 20); // 80-100%
      lightness = 45 + Math.floor(Math.random() * 15); // 45-60%
    }
    // 中等饱和度区（其他颜色区域）
    else {
      saturation = 70 + Math.floor(Math.random() * 25); // 70-95%
      lightness = 40 + Math.floor(Math.random() * 20); // 40-60%
    }

    randomColor = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
  } while (existingColors.includes(randomColor) || !isColorDistinct(randomColor, existingColors));

  return randomColor;
};

// 新增辅助函数：判断新颜色是否与已有颜色足够区分
function isColorDistinct(newColor, existingColors) {
  // 如果没有已有颜色，直接返回true
  if (existingColors.length === 0) return true;

  // 解析新颜色的HSL值
  const newHsl = parseHsl(newColor);

  // 检查新颜色与每个已有颜色的差异
  for (const color of existingColors) {
    const hsl = parseHsl(color);

    // 计算色调差异（考虑色环的循环性质）
    const hueDiff = Math.min(Math.abs(newHsl.h - hsl.h), 360 - Math.abs(newHsl.h - hsl.h));

    // 计算饱和度和亮度差异
    const satDiff = Math.abs(newHsl.s - hsl.s);
    const lightDiff = Math.abs(newHsl.l - hsl.l);

    // 如果颜色在所有维度上都过于接近，则认为不够区分
    if (hueDiff < 40 && satDiff < 20 && lightDiff < 15) {
      return false;
    }
  }

  return true;
}

// 新增辅助函数：解析HSL颜色字符串为对象
function parseHsl(hslString) {
  // 匹配HSL格式: hsl(h, s%, l%)
  const match = hslString.match(/hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/);
  if (match) {
    return {
      h: parseInt(match[1]),
      s: parseInt(match[2]),
      l: parseInt(match[3]),
    };
  }
  // 默认返回黑色
  return { h: 0, s: 0, l: 0 };
}

// 拆分文件名和扩展名的辅助函数
export const getFileNameParts = fileName => {
  const lastDotIndex = fileName.lastIndexOf('.');
  // 如果文件名中没有点或点在最后一位，则没有扩展名
  if (lastDotIndex === -1 || lastDotIndex === fileName.length - 1) {
    return {
      name: fileName,
      extension: '',
    };
  }
  // 提取文件名（不含扩展名）和扩展名
  const name = fileName.substring(0, lastDotIndex);
  const extension = fileName.substring(lastDotIndex); // 包含点号
  return { name, extension };
};

// 添加一个可复用的日期时间格式化工具函数
export const formatDateTime = (date = new Date(), format = 'YYYY-MM-DD HH:mm:ss') => {
  // 检查参数类型，处理只传入格式的情况
  // 如果第一个参数是字符串，那么它应该是格式参数
  if (typeof date === 'string') {
    format = date;
    date = new Date();
  }

  // 如果没有传入日期参数或日期参数无效，则使用当前时间
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    date = new Date();
  }

  // 如果没有传入格式参数，使用默认格式
  if (!format) {
    format = 'YYYY-MM-DD HH:mm:ss';
  }
  // 获取日期时间各部分的值
  const year = date.getFullYear();
  const month = date.getMonth() + 1; // 月份从0开始，需要+1
  const day = date.getDate();
  const hours = date.getHours();
  const minutes = date.getMinutes();
  const seconds = date.getSeconds();

  // 补零函数，确保数字为两位数
  const padZero = num => {
    return String(num).padStart(2, '0');
  };

  // 替换格式字符串中的占位符
  return format
    .replace('YYYY', year)
    .replace('MM', padZero(month))
    .replace('DD', padZero(day))
    .replace('HH', padZero(hours))
    .replace('mm', padZero(minutes))
    .replace('ss', padZero(seconds));
};

/**
 * 通过URL下载文件的公共方法 - 优化版，支持直接下载音频等媒体文件
 * @param {string} url - 文件下载地址
 * @param {string} [fileName] - 可选的文件名，如果不提供则从URL或响应头中获取
 * @returns {Promise<void>} - 返回Promise表示下载操作的完成状态
 */
export const fetchDownloadFile = async (url, fileName) => {
  try {
    // 使用fetch API获取文件的blob数据，确保直接下载而不是在浏览器中打开
    const response = await fetch(url, {
      method: 'GET',
      credentials: 'include', // 包含cookie信息，处理需要登录的情况
      headers: {
        'Content-Type': 'application/octet-stream', // 表示二进制数据流
      },
    });

    if (!response.ok) {
      throw new Error(`HTTP错误! 状态码: ${response.status}`);
    }

    // 将响应转换为blob对象
    const blob = await response.blob();

    // 创建指向blob的URL
    const blobUrl = window.URL.createObjectURL(blob);

    // 创建临时链接元素
    const link = document.createElement('a');
    link.href = blobUrl;

    // 设置文件名称
    if (fileName) {
      link.download = fileName;
    } else {
      // 尝试从响应头获取文件名
      const contentDisposition = response.headers.get('content-disposition');
      if (contentDisposition) {
        const match = contentDisposition.match(/filename="?([^;"\n]+)"?/);
        if (match && match[1]) {
          link.download = decodeURIComponent(match[1]);
        }
      }
    }

    // 隐藏链接并添加到文档中
    link.style.display = 'none';
    document.body.appendChild(link);

    // 触发点击事件开始下载
    link.click();

    // 下载完成后清理资源
    setTimeout(() => {
      document.body.removeChild(link);
      // 释放blob URL资源，防止内存泄漏
      window.URL.revokeObjectURL(blobUrl);
    }, 100);
  } catch (error) {
    console.error('文件下载失败:', error);
    // 可以根据项目需求添加错误提示
    throw new Error('文件下载失败');
  }
};

/**
 * 下载媒体文件（音频/视频），在当前页面直接下载不跳转
 * @param {string} url - 媒体文件下载地址
 * @param {string} [fileName] - 可选的文件名
 * @param {string} [mediaType] - 媒体MIME类型，未指定则从文件名后缀推断
 * @returns {Promise<void>}
 */
export const downloadMedia = async (url, fileName, mediaType) => {
  // 媒体文件后缀与MIME类型映射表
  const mediaMimeMap = {
    // 音频类型
    mp3: 'audio/mpeg',
    wav: 'audio/wav',
    ogg: 'audio/ogg',
    flac: 'audio/flac',
    aac: 'audio/aac',
    m4a: 'audio/mp4',
    wma: 'audio/x-ms-wma',
    // 视频类型
    mp4: 'video/mp4',
    avi: 'video/x-msvideo',
    mov: 'video/quicktime',
    wmv: 'video/x-ms-wmv',
    flv: 'video/x-flv',
    mkv: 'video/x-matroska',
    webm: 'video/webm',
  };

  // 从文件名提取后缀并推断MIME类型
  const getMimeTypeFromFileName = name => {
    if (!name) return null;
    const extMatch = name.match(/\.([a-zA-Z0-9]+)$/);
    if (extMatch && extMatch[1]) {
      const ext = extMatch[1].toLowerCase();
      return mediaMimeMap[ext] || null;
    }
    return null;
  };

  // 判断MIME类型是音频还是视频
  const isVideoType = mimeType => {
    return mimeType.startsWith('video/');
  };

  try {
    // 处理文件名（用于MIME类型推断）
    let finalFileName = fileName;
    if (!finalFileName) {
      // 先从URL提取作为临时文件名
      const urlParts = url.split('/');
      finalFileName =
        urlParts.pop().split('?')[0] ||
        `${isVideoType(mediaType) ? 'video' : 'audio'}-${Date.now()}`;
    }

    // 确定媒体MIME类型：显式指定 > 从文件名推断 > 默认值
    let finalMediaType = mediaType;
    if (!finalMediaType) {
      // 尝试从文件名推断
      finalMediaType = getMimeTypeFromFileName(finalFileName);
      // 如果推断失败，根据可能的类型使用默认值
      if (!finalMediaType) {
        // 无法确定类型时先假设为视频，因为视频通常需要更明确的类型处理
        finalMediaType = 'video/mp4';
      }
    }

    // 使用fetch获取媒体文件
    const response = await fetch(url, {
      method: 'GET',
      credentials: 'include', // 携带认证信息
      headers: {
        Accept: finalMediaType,
      },
    });

    if (!response.ok) {
      throw new Error(`请求失败: ${response.status} ${response.statusText}`);
    }

    // 从响应头更新文件名（如果之前未获取到）
    if (!fileName) {
      const contentDisposition = response.headers.get('content-disposition');
      if (contentDisposition) {
        const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
        if (match && match[1]) {
          finalFileName = decodeURIComponent(match[1].replace(/['"]/g, ''));
          // 如果此时文件名有了新值，再次尝试推断MIME类型
          if (mediaType === undefined) {
            const inferredType = getMimeTypeFromFileName(finalFileName);
            if (inferredType) {
              finalMediaType = inferredType;
            }
          }
        }
      }
    }

    // 确保文件名有正确的扩展名
    if (!finalFileName.includes('.')) {
      const ext = Object.keys(mediaMimeMap).find(key => mediaMimeMap[key] === finalMediaType);
      finalFileName += ext ? `.${ext}` : isVideoType(finalMediaType) ? '.mp4' : '.mp3';
    }

    // 将响应转换为blob
    const blob = await response.blob();
    // 创建指向blob的URL
    const objectUrl = URL.createObjectURL(new Blob([blob], { type: finalMediaType }));

    // 创建并触发下载链接
    const link = document.createElement('a');
    link.href = objectUrl;
    link.download = finalFileName; // 关键：设置download属性强制下载
    link.style.display = 'none';

    // 添加到文档并触发点击
    document.body.appendChild(link);
    const event = new MouseEvent('click', {
      view: window,
      bubbles: true,
      cancelable: true,
    });
    link.dispatchEvent(event);

    // 清理资源
    setTimeout(() => {
      document.body.removeChild(link);
      URL.revokeObjectURL(objectUrl); // 释放blob URL，避免内存泄漏
    }, 100);
  } catch (error) {
    console.error('媒体下载失败:', error);
    throw new Error(`媒体下载失败: ${error.message}`);
  }
};

/**
 * 下载音频文件
 * @param {string} url - 音频文件URL
 * @param {string} [fileName] - 可选的自定义文件名
 * @returns {Promise<void>}
 */
export const downloadAudio = (url, fileName) => {
  return downloadMedia(url, fileName, 'audio/mpeg');
};

// 辅助函数：计算最大公约数
function calculateGCD(a, b) {
  return b === 0 ? a : calculateGCD(b, a % b);
}

// 封装的图片比例计算方法 - 支持文件和URL
export const getImageRatio = async source => {
  return new Promise((resolve, reject) => {
    try {
      const img = new Image();

      // 处理跨域问题
      img.crossOrigin = 'anonymous';

      img.onload = function () {
        const width = img.width;
        const height = img.height;

        // 计算宽高比
        const ratio = (width / height).toFixed(4);

        // 计算最大公约数以简化比例
        const gcd = calculateGCD(width, height);
        const simplifiedWidth = width / gcd;
        const simplifiedHeight = height / gcd;

        // 返回计算结果
        resolve({
          width,
          height,
          ratio: parseFloat(ratio),
          simplifiedRatio: `${simplifiedWidth}:${simplifiedHeight}`,
          originalRatio: `${width}:${height}`,
          src: img.src, // 返回图片源地址
        });
      };

      img.onerror = function () {
        reject(new Error('无法加载图片，请检查图片源是否有效'));
      };

      // 根据源类型设置图片源
      if (source instanceof File) {
        // 如果是文件对象，使用FileReader读取
        const reader = new FileReader();
        reader.onload = function (e) {
          img.src = e.target.result;
        };
        reader.onerror = function () {
          reject(new Error('文件读取失败'));
        };
        reader.readAsDataURL(source);
      } else if (
        typeof source === 'string' &&
        (source.startsWith('http://') || source.startsWith('https://'))
      ) {
        // 如果是URL字符串
        img.src = source;
      } else {
        reject(new Error('不支持的图片源类型，请提供文件对象或有效的URL'));
      }
    } catch (error) {
      reject(error);
    }
  });
}

// 将输入比例转换为数值
const parseRatio = ratio => {
  if (typeof ratio === 'number') {
    return ratio; // 已经是数值，直接返回
  }

  if (typeof ratio === 'string') {
    // 处理字符串格式，如'16:9'
    if (ratio.includes(':')) {
      const [width, height] = ratio.split(':').map(Number);
      if (width && height) {
        return width / height;
      }
    }
    // 如果是纯数字字符串，转换为数值
    return parseFloat(ratio);
  }

  if (Array.isArray(ratio)) {
    // 如果是数组，递归处理每个元素
    return ratio.map(item => parseRatio(item));
  }

  throw new Error('不支持的输入格式');
};

/**
 * 验证图片比例是否符合要求
 * @param {number|string|Array} inputRatio - 输入的比例值，支持多种格式：
 *   - number: 直接的比例值，如0.5625 (9/16)
 *   - string: 简化比格式，如'16:9'、'9:16'、'1:1'
 *   - Array: 比例范围数组，如['16:9', '9:16', '1:1']
 * @param {number|string|Array} targetRatios - 目标比例，支持与inputRatio相同的格式
 * @param {number} floatRange - 浮动范围，默认为0.2
 * @returns {boolean} 是否符合要求
 */
export const validateImageRatio = (inputRatio, targetRatios, floatRange = 0.2) => {
  // 获取目标比例数值数组
  const getTargetRatioValues = ratios => {
    const parsed = parseRatio(ratios);
    return Array.isArray(parsed) ? parsed : [parsed];
  };

  try {
    // 解析输入比例
    const inputRatioValue = parseRatio(inputRatio);

    // 解析目标比例
    const targetRatioValues = getTargetRatioValues(targetRatios);

    // 验证是否在允许的浮动范围内
    return targetRatioValues.some(targetRatio => {
      const ratioDiff = Math.abs(targetRatio - inputRatioValue);
      return ratioDiff <= floatRange;
    });
  } catch (error) {
    console.error('比例验证失败:', error);
    return false;
  }
};

/**
 * 获取常见比例对应的数值
 * @param {string} ratioName - 比例名称，如'16:9', '9:16', '1:1', '4:3', '3:2'
 * @returns {number} 比例数值
 */
export const getCommonRatioValue = ratioName => {
  const commonRatios = {
    '16:9': 16 / 9,
    '9:16': 9 / 16,
    '1:1': 1,
    '4:3': 4 / 3,
    '3:2': 3 / 2,
    '21:9': 21 / 9,
    '9:21': 9 / 21,
  };

  return commonRatios[ratioName] || parseRatio(ratioName);
};
